#include "cfcgl.h"
#include "UIBuf.h"
#include "Div.h"
#include "Interface.h"
#include <algorithm>
namespace cfcgl
{
    Coord screenSize;
    unique_ptr<Interface>itf;
    vector<vector<Pixel>>screen;
    vector<vector<Pixel>>back;
    vector<CUIBuf*>uibufs;
    Format DefaultFormat;
    Format painter;
    vector<vector<CUIBuf*>>pxtop;
    bool ScreenUpdatePending;
    CDiv* focus;
    CDiv* background;
    void UpdatePixel(Coord pos)
    {
        std::sort(uibufs.begin(), uibufs.end());
        for (auto ri = uibufs.rbegin(); ri != uibufs.rend(); ri++)
        {
            if ((*ri)->_visible && included(pos, (*ri)->_pos, (*ri)->_size))
            {
                if (pxtop[pos.X][pos.Y] == *ri)
                    return;
                pxtop[pos.X][pos.Y] = *ri;
                screen[pos.X][pos.Y] = pxtop[pos.X][pos.Y]->at({ Length(pos.X - pxtop[pos.X][pos.Y]->_pos.X), Length(pos.Y - pxtop[pos.X][pos.Y]->_pos.Y) });
                ScreenUpdatePending = true;
                return;
            }
        }
        if (screen[pos.X][pos.Y] != Pixel({ ' ', DefaultFormat }))
            screen[pos.X][pos.Y] = { ' ',DefaultFormat },
            ScreenUpdatePending = true;
        return;
    }
    void UpdatePainter(Format& a, const Format& b)
    {
        if (a.bold != b.bold)
            itf->FontBold(b.bold);
        if (a.udl != b.udl)
            itf->FontUnderline(b.udl);
        if (b._BgC != NC)
            if (a._BgC != b._BgC)
                itf->SetBackgroundColor(b._BgC);
            else;
        else
            if (a._BgC != NC || a._BgR != b._BgR || a._BgG != b._BgG || a._BgB != b._BgB)
                itf->SetBackgroundColorEx(b._BgR, b._BgG, b._BgB);
        if (b._FgC != NC)
            if (a._FgC != b._FgC)
                itf->SetForegroundColor(b._FgC);
            else;
        else
            if (a._FgC != NC || a._FgR != b._FgR || a._FgG != b._FgG || a._FgB != b._FgB)
                itf->SetForegroundColorEx(b._FgR, b._FgG, b._FgB);
        a = b;
    }
    void UpdateScreenUIBuffer(bool force)
    {
        for (unsigned short i = 0; i < screenSize.X; i++)
        {
            for (unsigned short j = 0; j < screenSize.Y; j++)
            {
                if (force || screen[i][j] != back[i][j])
                {
                    UpdatePainter(painter, screen[i][j].format);
                    itf->SetCoord({ i, j });
                    putchar(screen[i][j].ch);
                    back[i][j] = screen[i][j];
                }
            }
        }
    }
    void NextTab()
    {
        if (focus->ChildBegin == nullptr)
        {
        _nxtb_kel:
            if (focus->next == nullptr)
            {
                focus = focus->ParentElement;
                goto _nxtb_kel;
            }
            else
                focus = focus->next;
        }
        else
            focus = focus->ChildBegin;
        if (focus->_visible == false)
            goto _nxtb_kel;
        else if (focus->userSelect == false)
            NextTab();
    }
    void LastTab()
    {
        if (focus->prev == nullptr)
        {
            focus = focus->ParentElement;
            if (focus->userSelect == false)
                LastTab();
        }
        else
        {
            focus = focus->prev;
        _lstb_kel:
            if (focus->_visible == false)
                LastTab();
            else if (focus->userSelect == false)
            {
                if (focus->ChildEnd == nullptr)
                    LastTab();
                else
                {
                    focus = focus->ChildEnd;
                    goto _lstb_kel;
                }
            }
        }
    }
    void init(Coord size, bool EnableVT)
    {
        screenSize = size;
        screen.resize(size.X);
        pxtop.resize(size.X);
        if (EnableVT)
            cfcgl::itf.reset(new IfVT());
        else
            cfcgl::itf.reset(new IfnVT());
        for (int i = 0; i < size.X; i++)
        {
            screen[i].resize(size.Y);
            pxtop[i].resize(size.Y);
            for (int j = 0; j < size.Y; j++)
            {
                cfcgl::screen[i][j] = { ' ',DefaultFormat };
                pxtop[i][j] = nullptr;
            }
        }
        back = screen;
        painter = DefaultFormat;
        UpdateScreenUIBuffer(true);
        background = new CDiv();
        background->SetPos({ 0,0 });
        background->resize({ screenSize.X, screenSize.Y });
        background->SetRel(Relation::fixed);
        background->SetzIndex(0);
        background->Show(true);
    }
}